Welcome.
In this lecture, we're going to be learning about the pathfinding service, which allows you to move
a humanoid character rig towards a desired destination along a computed path.
So let's get started.
Now I'm going to be using this little setup area I've got here to demonstrate the pathfinding service.
If you would like to use the same setup that I have here, then I will have this model attached to the
lecture for you to use.
Otherwise we can head to the avatar tab and create a new AR 15 rig.
I'll just make a block avatar and this guy is going to act as our AI.
So inside of him we can go ahead and create a new server script that's going to move him around along
a computed path.
Of course, one of the first things we're going to need is the pathfinding service.
So we'll make a variable.
We'll call it pathfinding service and that's equal to game get service pathfinding service.
Then we can go ahead and refer to the rig which is script dot parent.
We'll get his humanoid which is equal to rig dot humanoid.
And then we also want to get the goal part that I have in the workspace that we want our rig to move
to, which is this part right here.
So we'll make a reference to this goal part.
And that's in my workspace dot goal.
Now inside of the pathfinding service there is a function called create path, and this returns to us
a path instance.
And we can use this path instance to compute paths around our map from a starting point and an ending
point, and we can pass to this function something called agent parameters, which is a table that gives
us some customization of how we would like this path to be computed.
So what I'm going to do is I'm going to create a new table and I'm going to call it my agent params.
And we're going to pass agent params to my create path function.
Now, inside of this table, we have access to several different properties to manipulate how we want
this path to behave.
For example, one of the first ones is called Agent Radius.
And this defines the minimum amount of horizontal space required to be considered traversable for our
humanoid.
So this value should be half the width of your character at minimum.
And that's because if you were to set this value to something like 0.5, well, clearly the width of
our character is not going to be one stud or 0.5 radius.
And because of that, our rig is not going to be able to traverse through spaces that have a width of
one stud, because the total width of our character is not one stud.
In fact, our humanoid root part, which is the area that's going to be colliding, has a width of two
studs.
So at minimum, this value should be half the width of your humanoid root part.
So we can go ahead and refer to our rig, get the humanoid root part, get it size on the x axis and
divide it by two to get the radius.
So that's going to be our agent radius.
The next property is going to be called agent height.
And this is the same thing as agent Radius except it defines the minimum amount of vertical space required
to be considered traversable for our humanoid.
So default humanoid rigs are about five studs in height.
So we want to make sure that we set this height value to be at least the height of our AI rig.
So I'm going to set it to five.
The next property is called Agent Can Jump.
And this allows us to tell the pathfinding service if it's okay for our AI to jump at certain areas
in a path to reach the destination.
So for example, here along this route, clearly our rig is going to have to jump over this gap and
jump over this gap.
If we do not set this to true, then our AI is going to avoid going this way because our AI can't jump.
So it's going to try and find a different way to get to our point right here.
But I'm going to set agent can jump equal to true.
And then the next property is called agent can climb.
And this allows us to tell the pathfinding service if it's okay for our AI to climb.
Trust parts.
So for example if our agent can't jump, but let's say he can climb a trust part, then he'll path find
and climb up this trust part to reach to our point.
So we're going to set this to false for now.
And then the next property is called waypoint spacing, and this allows us to control how detailed we
would like the path to be.
The number that we pass here is going to represent the spacing and studs between waypoints along a path.
For example, a value of four would mean that each waypoint has a distance of four studs in between
them, while a value of like 0.5 would mean each waypoint has a distance of 0.5 studs between them,
so you'll have a lot more waypoints with a smaller waypoint spacing, which makes your path more detailed.
But I'm going to set this value at the default of four.
And then the last parameter we can go ahead and define in here is going to be a table called costs.
And what this has to be is a dictionary that contains key value pairs, and the keys must be the name
of either materials or the labels of pathfinding modifiers in our game.
And then you can assign a value to those keys to represent the cost of your AI traversing through that
specific material, or a specific part that has a pathfinding modifier inside of it.
So if the cost is very high, then the pathfinding service will try to compute a path to avoid walking
over that specific material as much as possible.
For example, if I don't want my AI to walk over the material of cracked lava, then to have my AI completely
avoid the material of cracked lava, then I can set the value equal to math dot huge.
And this means my AI will never, ever compute a path over this material.
You also heard me talk about pathfinding modifiers earlier.
So if I were to go to this part, I actually already have a pathfinding modifier in here, but I'll
just create another one.
So we'll create and add a new pathfinding modifier as a child of this part.
And here we can give a label for this pathfinding modifier.
I'm going to call this my avoid part.
And I don't want my AI to be able to walk or traverse over this particular part.
So that means inside of my cost table, I can go ahead and refer to the label that I gave to this pathfinding
modifier, which is avoid part.
And I can also set its value equal to math dot huge.
And now my AI is never ever going to walk over that part.
So now that we have our agent parameters set up, this function is going to return to us a path instance.
So I'll store it in a variable, I'll call it my path.
And then for the sake of this lecture I'm going to type annotate it as a path.
So we get access to all of the autofill features.
You don't have to worry about type annotation, but I'm just going to do this for the sake of the lecture.
And now what we can go ahead and do is refer to this path.
And there's a function inside of it called compute async and it says computes a path from a start point
to an end position.
The starting position would be the position of our humanoid.
So we would do rig dot humanoid route part.
That position.
And then the end goal is going to be our goal parts position.
So we'll get our goal and pass the position.
Once it computes the path, then it's going to tell us whether or not it was successful.
So inside of our path we also have another property called status.
And it says the success of the generated path.
So if the status is equal to the enum dot path status dot success, then that means it has successfully
generated a path for us to use.
So we're going to check if we were successful.
And if we did, then this is where we're going to loop through every single waypoint that was generated
by our path, and move our humanoid along those waypoints.
Otherwise, if we were not successful, then we can warn and say something like fail to compute path,
and then we can go ahead and print out what the status is in the console.
Otherwise, what we can go ahead and do is we can loop through every single waypoint that is inside
of our path, and we can get those waypoints because our path has a function called get waypoints and
it says returns an array of points in the path.
And I'm also going to type annotate this as well to declare as a path waypoint.
And this point has a couple of properties inside of it that defines the position, as well as the action
to perform for the humanoid.
So, for example, some of our waypoints are going to notify us that we need to jump over a gap.
So that means the point dot action is going to be set equal to the enum dot waypoint action path waypoint
action dot jump.
So if the action we need to perform is to jump, then we want to force our humanoid to jump.
And that's very easy to do.
We can set the humanoid dot jump property equal to true.
However, before we have our humanoid jump, we obviously want to move them towards the position of
this waypoint.
So inside of our humanoid we have a function called move two and it says causes the humanoid to attempt
to walk to the given location.
By setting the humanoid walk to point and humanoid walk two part properties.
So the location we want the humanoid to move to is going to be our point dot position.
So then our humanoid is going to move to this position.
If we need to jump, we're going to force our humanoid to jump.
And then what we need to do is we need to wait for our humanoid to actually make it to this position.
If we don't put a yield statement in here, then this for loop is going to basically execute instantaneously
and our AI is going to mess up.
So thankfully, inside of our humanoid there is an event called Move to Finished Fires.
When the humanoid finishes walking to a goal declared by Humanoid move two.
So we're going to wait for this event to fire before we move on to the next waypoint.
Now, to make this easier to visualize, we can go ahead and loop through every single waypoint inside
of our path and create a part to represent the position of that waypoint like you saw in the beginning
of the lecture.
So I'm going to again loop through every single point and pass a get waypoints.
And I'm going to create a new part.
So instance dot new part I'm going to set the shape of my part equal to the enum dot part type dot ball.
We can set the size equal to a new vector three of 111.
We'll set the color equal to a new color three and I'll just make it a bright green.
We'll set the material equal to the enum dot material, dot neon, and then we'll make sure to anchor
our part.
We'll make sure can collide is set to false.
And then we'll update the position to be equal to this waypoints position.
And then we can set the parent equal to the workspace.
So now when this code executes, it's going to compute a path for our rig to reach our goal position.
And if it's successful then we're going to walk to each one of those waypoints.
And we should see a part to visualize each one of those waypoint positions.
So let's go ahead and run our game and see what our AI does.
So if I hit run here.
As you can see, our humanoid is moving.
He jumps and then he's going to jump again.
And now he has reached his final destination.
So here you can see each of the individual waypoints that was generated for our humanoid to walk along.
And as you can also tell, the distance between these two waypoints are on average about four studs
apart.
Of course, there are a couple of other waypoints that are set a little bit closer, and that's because
you're not able to space this one four studs away from this other one.
Otherwise you're going to be falling down.
And this is the waypoint right here where it's telling us, hey, we got to jump or else we're going
to fall.
So it forces our humanoid to jump.
And then it forces our humanoid to jump again and we reach our final destination.
Now something very cool we can go ahead and take a look at, is that our AI is going to avoid walking
on these two parts, and that's because this one has a pathfinding modifier inside of it, and this
one is set to Cracked Lava.
And if you remember, we set the cost of this material and this part to be huge.
So our AI should avoid walking on these two parts.
So if I run my game.
As you can see, my eye is avoiding those two ramps, and he's going around and taking the long way
to reach our destination.
However, something I can go ahead and do is I can set the agent can climb property equal to true.
And now if we run our game, our humanoid should instead.
As you can see, he's going to our truss, he's climbing to it and now he's at the waypoint.
So the pathfinding service is always going to calculate the shortest possible path to reach a particular
desired position.
And then we can go ahead and alter the pathing of the pathfinding service based on these pathfinding
modifiers, as well as setting the costs for different materials.
Now, if I set the cost of cracked lava to be a value of like ten, but I were to set the cost of plastic
to be equal to 15.
Well, now.
My.
I should go and walk along this lava because it costs more to pathfind on this plastic than it does
on the lava.
Plus, this plastic is farther away from my humanoid to walk onto it.
So our pathfinding.
I should make a path along this lava ramp and reach our destination.
So let's go ahead and try it out.
If we run.
As you can see, our AI calculated.
Hey, the cost for this particular material wasn't that high.
So let's go ahead and pathfind on to it.
Now, if I set the cost a lot higher, then our AI should instead decide to go and pathfind on to this
truss instead.
So if I set the value of cracked lava to something like 500, then our AI is like, nope, we're not
going to walk on cracked lava.
Instead, we're going to go and climb up our truss part instead.
Though the pathfinding service gives us a lot of options to tweak how we want our rigs in our game to
pathfind to certain areas, the service can be incredibly fun and useful to use.
Anyways, that's all I have for you in this lecture.
I'll see you in the next one.